package org.mybatis.generator.plugins;

import com.itfsw.mybatis.generator.plugins.utils.PluginTools;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.entity.ColumnMeta;
import org.mybatis.generator.entity.TableMeta;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @author hedong
 * @version 1.0
 * @date 2020/6/18
 * @since JDK1.8
 */
public class TypeHandlerPlugin extends PluginAdapter {

    private static final Logger LOGGER = LoggerFactory.getLogger(TypeHandlerPlugin.class);

    private static final Map<String, Class<?>> ARRYTYPE_CLASS_MAP = new HashMap<>();

    private static final Class<Object[]> OBJECT_ARRAY_CLASS = Object[].class;

    private static final Class<Object> OBJECT_CLASS = Object.class;

    static {
        ARRYTYPE_CLASS_MAP.put("_char", String[].class);
        ARRYTYPE_CLASS_MAP.put("_varchar", String[].class);
        ARRYTYPE_CLASS_MAP.put("_boolean", Boolean[].class);
        ARRYTYPE_CLASS_MAP.put("_bool", Boolean[].class);
        ARRYTYPE_CLASS_MAP.put("_numeric", BigDecimal[].class);
        ARRYTYPE_CLASS_MAP.put("_int", Integer[].class);
        ARRYTYPE_CLASS_MAP.put("_int2", Integer[].class);
        ARRYTYPE_CLASS_MAP.put("_int4", Integer[].class);
        ARRYTYPE_CLASS_MAP.put("_int8", Long[].class);
        ARRYTYPE_CLASS_MAP.put("_smallint", Integer[].class);
        ARRYTYPE_CLASS_MAP.put("_integer", Integer[].class);
        ARRYTYPE_CLASS_MAP.put("_bigserial", Long[].class);
    }

    @Override
    public boolean validate(List<String> warnings) {
        boolean dependencyPlugin = PluginTools.checkDependencyPlugin(getContext(), OriginTableMetaPlugin.class);
        if (!dependencyPlugin) {
            LOGGER.warn("TypeHandlerPlugin未能生效,因为没有检测到它所依赖的Plugin:OriginTableMetaPlugin");
            return false;
        }
        return true;
    }

    @Override
    public void initialized(IntrospectedTable introspectedTable) {
        try {
            List<IntrospectedColumn> allColumns = introspectedTable.getAllColumns();
            Properties properties = getProperties();
            for (IntrospectedColumn column : allColumns) {
                // 不是ARRAY 和 OTHER 不做处理, 以原始的为准
                if (!(JdbcType.ARRAY.TYPE_CODE == column.getJdbcType() || JdbcType.OTHER.TYPE_CODE == column.getJdbcType())) {
                    continue;
                }
                // 获取数据库中的原始类型
                String columnName = column.getActualColumnName();
                TableMeta tableMeta = (TableMeta) introspectedTable.getAttribute(OriginTableMetaPlugin.ORIGIN_TABLE_META);
                ColumnMeta columnMeta = tableMeta.getColumnMeta(columnName);
                String columnType = columnMeta.getColumnType();

                // 获取配置中数据库类型对应的 typeHandler 的名称
                String typeHandlerClassName;
                //  以 "_" 开头的就是数组
                if (columnType.startsWith("_")) {
                    typeHandlerClassName = properties.getProperty("array");
                } else {
                    typeHandlerClassName = properties.getProperty(columnType);
                }
                if (StringUtils.isBlank(typeHandlerClassName)) {
                    continue;
                }

                String typeHandler = column.getTypeHandler();
                if (StringUtils.isBlank(typeHandler)) {
                    // 设置typeHandler
                    column.setTypeHandler(typeHandlerClassName);
                }

                // 设置java类中字段的类型
                String fullyQualifiedName = column.getFullyQualifiedJavaType().getFullyQualifiedName();
                if (!fullyQualifiedName.equals(OBJECT_CLASS.getCanonicalName()) && !fullyQualifiedName.equals(OBJECT_ARRAY_CLASS.getCanonicalName())) {
                    continue;
                }

                Class<?> typeHandlerClass = Class.forName(typeHandlerClassName);
                Class<?> returnType = typeHandlerClass.getMethod("getResult", ResultSet.class, String.class).getReturnType();
                String returnTypeCanonicalName = returnType.getCanonicalName();
                if (JdbcType.ARRAY.TYPE_CODE == column.getJdbcType()) {
                    Class<?> filedClass = ARRYTYPE_CLASS_MAP.get(columnType);
                    if (filedClass != null && (returnTypeCanonicalName.equals(OBJECT_CLASS.getCanonicalName())
                            || returnTypeCanonicalName.equals(OBJECT_ARRAY_CLASS.getCanonicalName()))) {
                        column.setFullyQualifiedJavaType(new FullyQualifiedJavaType(filedClass.getCanonicalName()));
                    } else {
                        column.setFullyQualifiedJavaType(new FullyQualifiedJavaType(returnTypeCanonicalName));
                    }
                } else {
                    column.setFullyQualifiedJavaType(new FullyQualifiedJavaType(returnTypeCanonicalName));
                }

            }
        } catch (Exception e) {
            LOGGER.warn("TypeHandlerPlugin 初始化失败", e);
        }
        super.initialized(introspectedTable);
    }
}
